package com.cardrive.util;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.Log;

import com.cardrive.listeners.IMovementListener;
import com.cardrive.listeners.IRotationListener;

public class Sprite {

	private int startX, startY;
	public int x;
	public int y;
	private int width;
	private int height;
	private Bitmap image = null;
	private boolean visible;
	private boolean startToward;
	private boolean startMovePoint;
	private int hdirection;// 0 = Left 1 = Right
	private int vdirection;// 0 = Top 1 = Bottom
	private int movementSpeedX, movementSpeedY;
	private int vel;
	private Matrix matrix = null;
	private int angle = 0;
	private boolean pressed = false;
	private boolean isMoving = false;
	private Context context = null;

	private Bitmap imgDisabled = null;
	private Bitmap imgEnabled = null;
	private boolean isEnabled = true;

	private int endX = x;
	private int endY = y;
	private int endAngle = angle;

	private IMovementListener movementListener;
	private IRotationListener rotationListener;
	private boolean isRotating = false;
	private int rotationSpeed = 0;

	public Sprite(Context context, int resourceID, int x, int y) {
		this.context = context;
		Bitmap tempBitmap = Utils.decodeBitmap(this.context.getResources(),
				resourceID);
		this.x = x;
		this.y = y;
		this.setStartX(x);
		this.setStartY(y);
		this.startX = x;
		this.startY = y;
		this.width = tempBitmap.getWidth();
		this.height = tempBitmap.getHeight();
		this.image = tempBitmap;
		this.imgEnabled = tempBitmap;
		this.visible = true;
		this.setStartMovePoint(false);
		this.setStartToward(false);
		this.startToward = false;
		this.setHdirection(0);
		this.setVdirection(0);
		this.vel = 15;
		this.matrix = new Matrix();
	}

	public void setDisabled() {
		isEnabled = false;
		this.image = imgDisabled;
	}

	public void setEnabled() {
		isEnabled = true;
		if (this.image != null) {
			this.image.recycle();
		}
		this.image = imgEnabled;
	}

	public Rect getBounds() {
		Rect r = new Rect();
		r.top = (int) this.getY();
		r.left = (int) this.getX();
		r.bottom = (int) (this.getY() + this.getHeight());
		r.right = (int) (this.getX() + this.getWidth());
		return r;
	}

	public boolean collidesInPoint(float x, float y) {

		/*
		 * Rect rect = new Rect((int) x, (int) y, (int) x + 1, (int) y + 1); if
		 * (this.getBounds().intersect(rect)) return true;
		 * 
		 * return false;
		 */

		if (0 < x - this.x && x - this.x < image.getWidth() && 0 < y - this.y
				&& y - this.y < image.getHeight()) {
			return image.getPixel((int) x - this.x, (int) y - this.y) != Color.TRANSPARENT;
		} else {
			return false;
		}

	}

	public boolean isCollide(Sprite s) {
		if (this.getBounds().intersect(s.getBounds()))
			return true;
		return false;
	}

	public void move(int moveX, int moveY) {
		if (moveX > 0)
			hdirection = 1;
		else if (moveX < 0)
			hdirection = 0;
		else
			hdirection = -1;

		if (moveY > 0)
			vdirection = 1;
		else if (moveY < 0)
			vdirection = 0;
		else
			vdirection = -1;

		x = x + moveX;
		y = y + moveY;

	}

	public void setPosition(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public void setToStartPosition() {
		this.x = this.startX;
		this.y = this.startY;
	}

	public void render(Canvas canvas, Paint paint) {

		moveTowards();

		if (isMoving) {
			moveToPoint();
		}

		if (isRotating) {
			rotate();
		}

		if (visible) {

			matrix.reset();
			matrix.postTranslate(x, y);
			matrix.postRotate(angle, x + getWidth() / 2, y + getHeight() / 2);

			canvas.drawBitmap(getImage(), matrix, paint);

		}
	}

	public void setRefPosition(int x, int y) {
		this.x = x - this.getWidth() / 2;
		this.y = y - this.getHeight() / 2;
	}

	public boolean isCollide(Rect r) {
		if (this.getBounds().intersect(r))
			return true;
		return false;
	}

	public void checkTowardSpeed(int pointX, int pointY) {
		if (x < pointX)
			movementSpeedX = vel;
		else
			movementSpeedX = -vel;

		if (y < pointY)
			movementSpeedY = vel;
		else
			movementSpeedY = -vel;
		this.endX = pointX;
		this.endY = pointY;
	}

	/**
	 * Star rotation of the sprite.
	 * 
	 * @param endAngle
	 *            is the angle to rotate
	 */
	public void startRotating(int endAngle, int rotationSpeed) {
		this.endAngle = endAngle;
		this.rotationSpeed = rotationSpeed;
		isRotating = true;
	}

	/**
	 * Rotate the sprite from the current angle to endAngle. Call startRotation
	 * needed.
	 */
	public void rotate() {
		if (Math.abs(endAngle - angle) > Math.abs(rotationSpeed)) {
			angle = angle + rotationSpeed;
		} else {
			if (isRotating) {
				angle = endAngle;
				isRotating = false;
				if (rotationListener != null) {
					rotationListener.onRotationFinished();
				}
				Log.d("Sprite", "angle : " + angle);

			}

		}
	}

	/**
	 * move the sprite to its initial position
	 */
	public void moveTowards() {
		boolean horizontal = false, vertical = false;

		if (startToward) {
			if (Math.abs(x - startX) >= Math.abs(movementSpeedX)) {
				move(movementSpeedX, 0);
			} else {
				horizontal = true;
			}

			if (Math.abs(y - startY) >= Math.abs(movementSpeedY)) {
				move(0, movementSpeedY);
			} else {
				vertical = true;
			}

			if (horizontal == true && vertical == true) {
				endMotion();
			}
		}
	}

	/**
	 * Start moving the sprite from the current point (x,y) to the end
	 * point(endX,endY)
	 * 
	 * @param endX
	 *            end point in X axis
	 * @param endY
	 *            end point in Y axis
	 */
	public void startMoving(int endX, int endY, int movementSpeedX,
			int movementSpeedY) {
		isMoving = true;
		this.movementSpeedX = movementSpeedX;
		this.movementSpeedY = movementSpeedY;
		this.endX = endX;
		this.endY = endY;
	}

	/**
	 * Move the sprite one step from the current point (x,y) to the end point
	 * (endX,endY). Call starMoving is not needed.
	 * 
	 * @param endX
	 *            end point in X axis
	 * @param endY
	 *            end point in Y axis
	 */
	public void moveToPoint(int endX, int endY) {
		// is moving horizontally and vertically
		boolean horizontal = true, vertical = true;

		if (Math.abs(this.getX() - endX) >= Math.abs(movementSpeedX)) {
			move(movementSpeedX, 0);
		} else {
			horizontal = false;
		}

		if (Math.abs(this.getY() - endY) >= Math.abs(movementSpeedY)) {
			move(0, movementSpeedY);
		} else {
			vertical = false;
		}

		verifyEndMovement(horizontal, vertical);
	}

	/*
	 * Don't modify this function
	 */
	public void moveToPointReceipt() {
		// is moving horizontally and vertically
		boolean horizontal = true, vertical = true;

		if (Math.abs(this.getX() - endX) >= Math.abs(movementSpeedX)) {
			move(movementSpeedX, 0);
		} else {
			horizontal = false;
		}

		if (Math.abs(this.getY() - endY) >= Math.abs(movementSpeedY)) {
			move(0, movementSpeedY);
		} else {
			vertical = false;
		}

		if (horizontal == false && vertical == false) {
			endMotion(endX, endY);
		}
	}

	/**
	 * move the sprite from the current point (x,y) to the end point(endX,endY)
	 */
	private void moveToPoint() {
		// is moving horizontally and vertically
		boolean isMovingHorizontal = true, isMovingVertical = true;

		if (Math.abs(this.getX() - endX) > Math.abs(movementSpeedX)) {
			move(movementSpeedX, 0);
		} else {
			isMovingHorizontal = false;
		}

		if (Math.abs(this.getY() - endY) > Math.abs(movementSpeedY)) {
			move(0, movementSpeedY);
		} else {
			isMovingVertical = false;
		}

		verifyEndMovement(isMovingHorizontal, isMovingVertical);

	}

	private void verifyEndMovement(boolean isMovingHorizontal,
			boolean isMovingVertical) {

		if (isMovingHorizontal == false && isMovingVertical == false) {
			if (isMoving == true) {
				endMotion(endX, endY);
				isMoving = false;
				if (movementListener != null) {
					movementListener.onMovementFinished();
				}
			}
		}
	}

	private void endMotion(int pointX, int pointY) {
		this.setPosition(pointX, pointY);
		if (isStartToward())
			setStartToward(false);
		if (isStartMovePoint())
			setStartMovePoint(false);
	}

	public void endMotion() {
		this.setPosition(startX, startY);
		startToward = false;
	}

	public int getStartX() {
		return startX;
	}

	public void setStartX(int startX) {
		this.startX = startX;
	}

	public int getStartY() {
		return startY;
	}

	public void setStartY(int startY) {
		this.startY = startY;
	}

	public boolean isVisible() {
		return visible;
	}

	public void setVisible(boolean visible) {
		this.visible = visible;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public int getHdirection() {
		return hdirection;
	}

	public void setHdirection(int hdirection) {
		this.hdirection = hdirection;
	}

	public int getVdirection() {
		return vdirection;
	}

	public void setVdirection(int vdirection) {
		this.vdirection = vdirection;
	}

	public boolean isStartToward() {
		return startToward;
	}

	public void setStartToward(boolean startToward) {
		this.startToward = startToward;
	}

	public int getSpeedX() {
		return movementSpeedX;
	}

	public void setMovementSpeedX(int speedX) {
		this.movementSpeedX = speedX;
	}

	public int getSpeedY() {
		return movementSpeedY;
	}

	public void setMovementSpeedY(int speedY) {
		this.movementSpeedY = speedY;
	}

	public boolean isStartMovePoint() {
		return startMovePoint;
	}

	public float getRotation() {
		return angle;
	}

	public void setStartMovePoint(boolean startMovePoint) {
		this.startMovePoint = startMovePoint;
	}

	public void setRotation(int rotation) {
		this.angle = rotation;
	}

	public int getVel() {
		return vel;
	}

	public Bitmap getImage() {
		if (isEnabled) {
			return image;
		} else {
			return imgDisabled;
		}
	}

	public void setVel(int vel) {
		this.vel = vel;
	}

	public void setImage(Bitmap image) {
		this.image = image;
		this.width = image.getWidth();
		this.height = image.getHeight();
	}

	public void setImgDisabled(Bitmap imgDisabled) {
		if (this.imgDisabled != null) {
			this.imgDisabled.recycle();
		}
		this.imgDisabled = imgDisabled;
	}

	public Bitmap getImgDisabled() {
		return imgDisabled;
	}

	public boolean isEnabled() {
		return isEnabled;
	}

	public void unloadResources() {
		if (imgDisabled != null) {
			imgDisabled.recycle();
			imgDisabled = null;
		}

		if (imgEnabled != null) {
			imgEnabled.recycle();
			imgEnabled = null;
		}

		if (image != null) {
			image.recycle();
			image = null;
		}

	}

	public boolean isPressed() {
		return pressed;
	}

	public void setPressed(boolean pressed) {
		this.pressed = pressed;
	}

	public IMovementListener getMovementListener() {
		return movementListener;
	}

	public void setMovementListener(IMovementListener movementListener) {
		this.movementListener = movementListener;
	}

	public boolean isMoving() {
		return isMoving;
	}

	public void setMoving(boolean isMoving) {
		this.isMoving = isMoving;
	}

	public IRotationListener getRotationListener() {
		return rotationListener;
	}

	public void setRotationListener(IRotationListener rotationListener) {
		this.rotationListener = rotationListener;
	}

	public int getAngle() {
		return angle;
	}

	public void setAngle(int angle) {
		this.angle = angle;
	}

}
